// 测试使用
#include <stdio.h>
#include <sys/time.h>
#include <sched.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <error.h>
#include <stdint.h>
// #include <netpacket/packet.h>
#include <pthread.h>
#include <unistd.h> // 系统调用相关的函数 close()
#include <string.h> // strcpy, memset(), and memcpy()
// #include <netdb.h>            // 网络相关的数据结构 struct addrinfo
#include <sys/types.h>       // 包含了一些基本的系统数据类型 uint8_t、uint16_t 和 uint32_t
#include <sys/socket.h>      // 与套接字相关的函数和数据结构
#include <netinet/in.h>      // 与 Internet 协议族相关的数据结构
#include <netinet/ip.h>      // IP 协议头部的数据结构
#include <netinet/ip_icmp.h> // 定义了 ICMP 协议头部的数据结构
#include <arpa/inet.h>       // 定义了一些 IP 地址转换函数
#include <sys/ioctl.h>       // 进行输入/输出控制的函数和相关宏
#include <bits/ioctls.h>     // 用于 ioctl() 函数的参数
#include <net/if.h>          // 处理网络接口相关的函数和数据结构
#include <linux/if_ether.h>  // 帧格式 以太网帧的一些常量
#include <linux/if_packet.h> // 用于与套接字相关联的网络接口的数据结构 struct sockaddr_ll
#include <net/ethernet.h>    // 以太网帧的数据结构
#include <errno.h>           // errno, perror()
#include <iostream>
// #include "linkdelaymeasure.h"
// #include "tsmp.h"
// #include "ptp.h"

#define ETH_P_DEAN 0x8585 // 自定义的以太网协议 type
#define PACKET_LEN 2048   // 数据包的最大长度为 2048 字节
#define PORT 8024

int sequence = 1;

struct Tsmp_rec_head
{
    uint8_t version;              // 版本号
    uint8_t type;                 // 类型
    uint8_t source_port;          // 源端口
    uint8_t reserve;              // 保留
    uint32_t local_time_sec;      // 本地时间秒时间戳
    uint32_t local_time_nanosec;  // 本地时间纳秒时间戳
    uint16_t ptcl_id;             // 协议标识
    uint16_t frame_id;            // 帧标识
    uint32_t global_time_sec;     // 全局时间秒时间戳
    uint32_t global_time_nanosec; // 全局时间纳秒时间戳 // 24字节
} __attribute__((packed));

// 封装接收帧负载
struct Pack_rec_payload
{
    uint8_t *ptp;
} __attribute__((packed));

struct Pack_rec // 封装接收帧
{
    struct Tsmp_rec_head head;
    struct Pack_rec_payload payload; // data
} __attribute__((packed));

struct PtpHeader
{
        uint8_t message_type : 4;
        uint8_t major_sdo_id : 4;
        uint8_t version_ptp : 4;
        uint8_t minor_version_ptp : 4;

        uint16_t message_length;
        uint8_t domain_number;
        uint8_t minor_sdo_id;
        uint16_t flags;
        uint64_t correction_field;
        uint32_t message_type_specific;
        uint8_t clock_identify[8];
        uint16_t port_number;
        uint16_t sequence_id;
        uint8_t control_field;
        uint8_t log_message_interval;
} __attribute__((packed));

struct Init_pack
{
        uint8_t padding[16]; // 正常情况24 测试是16
        PtpHeader ptp_header;
        uint8_t reserve[64]; // 空余64 以防越界
} __attribute__((packed));


enum PtpMsgType
{
    E_SYNC = 0x0,
    E_PDELAY_REQ = 0x2,
    E_PDELAY_RESP = 0x3,
    E_FOLLOW_UP = 0x8,
    E_PDELAY_RESP_FOLLOW_UP = 0xA,
    E_ANNOUNCE = 0xB,
    E_SIGNAL = 0xC,
};

struct Pack_rec packRec()
{
    struct Pack_rec tsmp_pack;

    int sd; // socket句柄
    struct sockaddr_ll device;
    struct ifreq ifr;

    // 创建套接字
    sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sd < 0)
    {
        printf("socket error\n");
    }
    memset(&device, 0, sizeof(struct sockaddr_ll));

    char buf[PACKET_LEN]; // data
    int len;

    memset(buf, 0, sizeof(buf)); // 刷新缓冲
    struct Pack_rec *eth = (struct Pack_rec *)buf;
    // 将字符数组 buf 转换为了 Pack_rec 类型的指针 eth
    // 直接通过 eth 指针来访问以太网帧中的各个字段
    // 接收数据

    while (1)
    {
        len = recvfrom(sd, buf, PACKET_LEN, 0, NULL, NULL);
        if (len < 0)
        {
            printf("recvfrom error, %d\n", errno);
            printf("\n");
        }
        if (ntohs(eth->head.ptcl_id) == 0xff01)
        {
            memcpy(&tsmp_pack.head, &eth->head, sizeof(struct Tsmp_rec_head));          // 打包头
            memcpy(&tsmp_pack.payload, &eth->payload, sizeof(struct Pack_rec_payload)); // 打包负载
            printf("tsmp版本：%02x\n", tsmp_pack.head.version);                             // 用于测试
            close(sd);  
            return tsmp_pack;
        }    
    }
}

int main()
{
    struct Pack_rec tsmp_pack = packRec();
    // 解析成为ptp
    struct Init_pack init_pack;
    memcpy(&init_pack, &tsmp_pack, sizeof(struct Init_pack));

    printf("tsmp版本16-19：%x\n", ntohl(tsmp_pack.head.global_time_sec));   // mac开始8字节
    printf("tsmp版本20-23：%x\n", ntohl(tsmp_pack.head.global_time_nanosec));

    for (int i = 0; i < sizeof(init_pack.padding); ++i) {
        printf("%02x ", init_pack.padding[i]);
    }
    printf("\n");


    printf("消息类型1：%x\n", ntohs(init_pack.ptp_header.major_sdo_id)); 
    printf("消息类型2：%x\n", ntohs(init_pack.ptp_header.message_type)); 
    printf("消息类型2：%x\n", ntohs(init_pack.ptp_header.minor_version_ptp)); 
    printf("消息类型3：%x\n", ntohs(init_pack.ptp_header.version_ptp));

    printf("message_length：%x\n", ntohs(init_pack.ptp_header.message_length));l

    printf("ab：%x\n", ntohs(init_pack.ptp_header.domain_number));
    printf("cd：%x\n", ntohs(init_pack.ptp_header.minor_sdo_id));

    printf("8：%x\n", ntohs(init_pack.ptp_header.flags));
    printf("correction_field：%x\n", ntohll(init_pack.ptp_header.correction_field));
    printf("message_type_specific：%x\n", ntohl(init_pack.ptp_header.message_type_specific));
    printf("clock_identify0)：%x\n", ntohs(init_pack.ptp_header.clock_identify[0]));
    printf("clock_identify1)：%x\n", ntohs(init_pack.ptp_header.clock_identify[1]));
    printf("clock_identify2)：%x\n", ntohs(init_pack.ptp_header.clock_identify[2]));
    printf("clock_identify3)：%x\n", ntohs(init_pack.ptp_header.clock_identify[3]));
    printf("clock_identify4)：%x\n", ntohs(init_pack.ptp_header.clock_identify[4]));
    printf("clock_identify5)：%x\n", ntohs(init_pack.ptp_header.clock_identify[5]));
    printf("clock_identify6)：%x\n", ntohs(init_pack.ptp_header.clock_identify[6]));
    printf("clock_identify7)：%x\n", ntohs(init_pack.ptp_header.clock_identify[7]));
    printf("端口0x6060：%x\n", ntohs(init_pack.ptp_header.port_number));

    printf("sequence_id：%x\n", ntohs(init_pack.ptp_header.sequence_id));
    printf("5：%x\n", ntohs(init_pack.ptp_header.control_field));
    printf("127：%x\n", ntohs(init_pack.ptp_header.log_message_interval));

    

    uint8_t type = init_pack.ptp_header.message_type;
    switch (type){
        case PtpMsgType::E_PDELAY_REQ: // 可以用
        printf("***\n");
    }
    return 0;
}